4 // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
6 // The use and distribution terms for this software are contained in the file
7 // named license.txt, which can be found in the root of this distribution.
8 // By using this software in any fashion, you are agreeing to be bound by the
9 // terms of this license.
11 // You must not remove this notice, or any other, from this software.
16 /* This class is used to wrap up compile-time constants in AST nodes.
17 For the most part, this means enums, primitives, strings, types and name spaces.
18 However, it can also be used to wrap the builtin objects when in Fast mode.
19 Addditionally null (Empty.Value), DBNull.Value and Missing.Value can be wrapped.
21 No other kind of value should be wrapped by this class.
24 namespace Microsoft
.JScript
{
27 using System
.Reflection
;
28 using System
.Reflection
.Emit
;
29 using System
.Globalization
;
31 internal class ConstantWrapper
: AST
{
32 internal Object
value;
33 internal bool isNumericLiteral
;
35 internal ConstantWrapper(Object
value, Context context
)
37 if (value is ConcatString
) value = value.ToString();
39 this.isNumericLiteral
= false;
42 internal override Object
Evaluate(){
46 internal override IReflect
InferType(JSField inference_target
){
47 if (this.value == null || this.value is DBNull
)
49 else if (this.value is ClassScope
|| this.value is TypedArray
)
51 else if (this.value is EnumWrapper
)
52 return ((EnumWrapper
)this.value).classScopeOrType
;
54 return Globals
.TypeRefs
.ToReferenceContext(this.value.GetType());
57 internal bool IsAssignableTo(Type rtype
){
59 Convert
.CoerceT(this.value, rtype
, false);
66 internal override AST
PartiallyEvaluate(){
70 public override String
ToString(){
71 return this.value.ToString();
74 internal override void TranslateToIL(ILGenerator il
, Type rtype
){
75 if (rtype
== Typeob
.Void
)
77 Object val
= this.value;
78 if (val
is EnumWrapper
&& rtype
!= Typeob
.Object
&& rtype
!= Typeob
.String
)
79 val
= ((EnumWrapper
)val
).value;
80 if (this.isNumericLiteral
&& (rtype
== Typeob
.Decimal
|| rtype
== Typeob
.Int64
|| rtype
== Typeob
.UInt64
|| rtype
== Typeob
.Single
))
81 val
= this.context
.GetCode();
82 if (!(rtype
is TypeBuilder
)){
84 val
= Convert
.CoerceT(val
, rtype
);
88 this.TranslateToIL(il
, val
, rtype
);
91 private void TranslateToIL(ILGenerator il
, Object val
, Type rtype
){
92 IConvertible ic
= Convert
.GetIConvertible(val
);
93 switch (Convert
.GetTypeCode(val
, ic
)){
95 il
.Emit(OpCodes
.Ldnull
);
96 if (rtype
.IsValueType
)
97 Convert
.Emit(this, il
, Typeob
.Object
, rtype
);
101 case TypeCode
.DBNull
:
102 il
.Emit(OpCodes
.Ldsfld
, Typeob
.Null
.GetField("Value"));
103 Convert
.Emit(this, il
, Typeob
.Null
, rtype
);
105 case TypeCode
.Boolean
:
106 ConstantWrapper
.TranslateToILInt(il
, ic
.ToInt32(null));
107 Convert
.Emit(this, il
, Typeob
.Boolean
, rtype
);
113 case TypeCode
.UInt16
:
115 ConstantWrapper
.TranslateToILInt(il
, ic
.ToInt32(null));
116 if (rtype
.IsEnum
) return;
117 if (val
is EnumWrapper
)
118 Convert
.Emit(this, il
, ((EnumWrapper
)val
).type
, rtype
);
120 Convert
.Emit(this, il
, Globals
.TypeRefs
.ToReferenceContext(val
.GetType()), rtype
);
122 case TypeCode
.UInt32
:
123 ConstantWrapper
.TranslateToILInt(il
, (int)ic
.ToUInt32(null));
124 if (rtype
.IsEnum
) return;
125 if (val
is EnumWrapper
)
126 Convert
.Emit(this, il
, ((EnumWrapper
)val
).type
, rtype
);
128 Convert
.Emit(this, il
, Typeob
.UInt32
, rtype
);
131 long l
= ic
.ToInt64(null);
132 if (Int32
.MinValue
<= l
&& l
<= Int32
.MaxValue
){
133 ConstantWrapper
.TranslateToILInt(il
, (int)l
);
134 il
.Emit(OpCodes
.Conv_I8
);
136 il
.Emit(OpCodes
.Ldc_I8
, l
);
137 if (rtype
.IsEnum
) return;
138 if (val
is EnumWrapper
)
139 Convert
.Emit(this, il
, ((EnumWrapper
)val
).type
, rtype
);
141 Convert
.Emit(this, il
, Typeob
.Int64
, rtype
);
143 case TypeCode
.UInt64
:
144 ulong ul
= ic
.ToUInt64(null);
145 if (ul
<= Int32
.MaxValue
){
146 ConstantWrapper
.TranslateToILInt(il
, (int)ul
);
147 il
.Emit(OpCodes
.Conv_I8
);
149 il
.Emit(OpCodes
.Ldc_I8
, (long)ul
);
150 if (rtype
.IsEnum
) return;
151 if (val
is EnumWrapper
)
152 Convert
.Emit(this, il
, ((EnumWrapper
)val
).type
, rtype
);
154 Convert
.Emit(this, il
, Typeob
.UInt64
, rtype
);
156 case TypeCode
.Single
:
157 float f
= ic
.ToSingle(null);
158 if (f
== f
&& (f
!= 0 || !Single
.IsNegativeInfinity(1 / f
))){
159 int i
= (int)Runtime
.DoubleToInt64(f
);
160 if (-128 <= i
&& i
<= 127 && f
== (float)i
){
161 ConstantWrapper
.TranslateToILInt(il
, i
);
162 il
.Emit(OpCodes
.Conv_R4
);
164 il
.Emit(OpCodes
.Ldc_R4
, f
);
166 il
.Emit(OpCodes
.Ldc_R4
, f
);
167 Convert
.Emit(this, il
, Typeob
.Single
, rtype
);
169 case TypeCode
.Double
:
170 double d
= ic
.ToDouble(null);
171 if (d
== d
&& (d
!= 0 || !Double
.IsNegativeInfinity(1 / d
))){
172 int i
= (int)Runtime
.DoubleToInt64(d
);
173 if (-128 <= i
&& i
<= 127 && d
== (double)i
){
174 ConstantWrapper
.TranslateToILInt(il
, i
);
175 il
.Emit(OpCodes
.Conv_R8
);
177 il
.Emit(OpCodes
.Ldc_R8
, d
);
179 il
.Emit(OpCodes
.Ldc_R8
, d
);
180 Convert
.Emit(this, il
, Typeob
.Double
, rtype
);
182 case TypeCode
.Decimal
:
183 int[] bits
= Decimal
.GetBits(ic
.ToDecimal(null));
184 ConstantWrapper
.TranslateToILInt(il
, bits
[0]);
185 ConstantWrapper
.TranslateToILInt(il
, bits
[1]);
186 ConstantWrapper
.TranslateToILInt(il
, bits
[2]);
187 il
.Emit(bits
[3] < 0 ? OpCodes
.Ldc_I4_1
: OpCodes
.Ldc_I4_0
); //bool isNegative
188 ConstantWrapper
.TranslateToILInt(il
, (bits
[3]&0x7FFFFFFF)>>16);
189 il
.Emit(OpCodes
.Newobj
, CompilerGlobals
.decimalConstructor
);
190 Convert
.Emit(this, il
, Typeob
.Decimal
, rtype
);
192 case TypeCode
.DateTime
:
193 l
= ic
.ToDateTime(null).Ticks
;
194 il
.Emit(OpCodes
.Ldc_I8
, l
);
195 Convert
.Emit(this, il
, Typeob
.Int64
, rtype
);
197 case TypeCode
.String
:
198 String str
= ic
.ToString(null);
199 if (rtype
== Typeob
.Char
&& str
.Length
== 1){
200 ConstantWrapper
.TranslateToILInt(il
, (int)str
[0]);
203 il
.Emit(OpCodes
.Ldstr
, str
);
204 Convert
.Emit(this, il
, Typeob
.String
, rtype
);
208 if (rtype
== Typeob
.String
)
209 this.TranslateToIL(il
, val
.ToString(), rtype
);
210 else if (rtype
.IsPrimitive
)
211 this.TranslateToIL(il
, System
.Convert
.ChangeType(val
, Enum
.GetUnderlyingType(Globals
.TypeRefs
.ToReferenceContext(val
.GetType())), CultureInfo
.InvariantCulture
), rtype
);
213 Type et
= Globals
.TypeRefs
.ToReferenceContext(val
.GetType());
214 Type ut
= Enum
.GetUnderlyingType(et
);
215 this.TranslateToIL(il
, System
.Convert
.ChangeType(val
, ut
, CultureInfo
.InvariantCulture
), ut
);
216 il
.Emit(OpCodes
.Box
, et
);
217 Convert
.Emit(this, il
, Typeob
.Object
, rtype
);
221 if (val
is EnumWrapper
){
222 if (rtype
== Typeob
.String
)
223 this.TranslateToIL(il
, val
.ToString(), rtype
);
224 else if (rtype
.IsPrimitive
)
225 this.TranslateToIL(il
, ((EnumWrapper
)val
).ToNumericValue(), rtype
);
227 Type et
= ((EnumWrapper
)val
).type
;
228 Type ut
= Globals
.TypeRefs
.ToReferenceContext(((EnumWrapper
)val
).value.GetType());
229 this.TranslateToIL(il
, ((EnumWrapper
)val
).value, ut
);
230 il
.Emit(OpCodes
.Box
, et
);
231 Convert
.Emit(this, il
, Typeob
.Object
, rtype
);
236 il
.Emit(OpCodes
.Ldtoken
, (Type
)val
);
237 il
.Emit(OpCodes
.Call
, CompilerGlobals
.getTypeFromHandleMethod
);
238 Convert
.Emit(this, il
, Typeob
.Type
, rtype
);
239 }else if (val
is Namespace
){
240 il
.Emit(OpCodes
.Ldstr
, ((Namespace
)val
).Name
);
241 this.EmitILToLoadEngine(il
);
242 il
.Emit(OpCodes
.Call
, CompilerGlobals
.getNamespaceMethod
);
243 Convert
.Emit(this, il
, Typeob
.Namespace
, rtype
);
244 }else if (val
is ClassScope
){
245 il
.Emit(OpCodes
.Ldtoken
, ((ClassScope
)val
).GetTypeBuilderOrEnumBuilder());
246 il
.Emit(OpCodes
.Call
, CompilerGlobals
.getTypeFromHandleMethod
);
247 Convert
.Emit(this, il
, Typeob
.Type
, rtype
);
248 }else if (val
is TypedArray
){
249 il
.Emit(OpCodes
.Ldtoken
, Convert
.ToType((TypedArray
)val
));
250 il
.Emit(OpCodes
.Call
, CompilerGlobals
.getTypeFromHandleMethod
);
251 Convert
.Emit(this, il
, Typeob
.Type
, rtype
);
252 }else if (val
is NumberObject
){
253 this.TranslateToIL(il
, ((NumberObject
)val
).value, Typeob
.Object
);
254 this.EmitILToLoadEngine(il
);
255 il
.Emit(OpCodes
.Call
, CompilerGlobals
.toObjectMethod
);
256 Convert
.Emit(this, il
, Typeob
.NumberObject
, rtype
);
257 }else if (val
is StringObject
){
258 il
.Emit(OpCodes
.Ldstr
, ((StringObject
)val
).value);
259 this.EmitILToLoadEngine(il
);
260 il
.Emit(OpCodes
.Call
, CompilerGlobals
.toObjectMethod
);
261 Convert
.Emit(this, il
, Typeob
.StringObject
, rtype
);
262 }else if (val
is BooleanObject
){
263 il
.Emit(((BooleanObject
)val
).value ? OpCodes
.Ldc_I4_1
: OpCodes
.Ldc_I4_0
);
264 il
.Emit(OpCodes
.Box
, Typeob
.Boolean
);
265 this.EmitILToLoadEngine(il
);
266 il
.Emit(OpCodes
.Call
, CompilerGlobals
.toObjectMethod
);
267 Convert
.Emit(this, il
, Typeob
.BooleanObject
, rtype
);
268 }else if (val
is ActiveXObjectConstructor
){
269 il
.Emit(OpCodes
.Call
, Typeob
.GlobalObject
.GetProperty("ActiveXObject").GetGetMethod());
270 Convert
.Emit(this, il
, Typeob
.ScriptFunction
, rtype
);
271 }else if (val
is ArrayConstructor
){
272 il
.Emit(OpCodes
.Call
, Typeob
.GlobalObject
.GetProperty("Array").GetGetMethod());
273 Convert
.Emit(this, il
, Typeob
.ScriptFunction
, rtype
);
274 }else if (val
is BooleanConstructor
){
275 il
.Emit(OpCodes
.Call
, Typeob
.GlobalObject
.GetProperty("Boolean").GetGetMethod());
276 Convert
.Emit(this, il
, Typeob
.ScriptFunction
, rtype
);
277 }else if (val
is DateConstructor
){
278 il
.Emit(OpCodes
.Call
, Typeob
.GlobalObject
.GetProperty("Date").GetGetMethod());
279 Convert
.Emit(this, il
, Typeob
.ScriptFunction
, rtype
);
280 }else if (val
is EnumeratorConstructor
){
281 il
.Emit(OpCodes
.Call
, Typeob
.GlobalObject
.GetProperty("Enumerator").GetGetMethod());
282 Convert
.Emit(this, il
, Typeob
.ScriptFunction
, rtype
);
283 }else if (val
is ErrorConstructor
){
284 ErrorConstructor error
= (ErrorConstructor
)val
;
285 if (error
== ErrorConstructor
.evalOb
)
286 il
.Emit(OpCodes
.Call
, Typeob
.GlobalObject
.GetProperty("EvalError").GetGetMethod());
287 else if (error
== ErrorConstructor
.rangeOb
)
288 il
.Emit(OpCodes
.Call
, Typeob
.GlobalObject
.GetProperty("RangeError").GetGetMethod());
289 else if (error
== ErrorConstructor
.referenceOb
)
290 il
.Emit(OpCodes
.Call
, Typeob
.GlobalObject
.GetProperty("ReferenceError").GetGetMethod());
291 else if (error
== ErrorConstructor
.syntaxOb
)
292 il
.Emit(OpCodes
.Call
, Typeob
.GlobalObject
.GetProperty("SyntaxError").GetGetMethod());
293 else if (error
== ErrorConstructor
.typeOb
)
294 il
.Emit(OpCodes
.Call
, Typeob
.GlobalObject
.GetProperty("TypeError").GetGetMethod());
295 else if (error
== ErrorConstructor
.uriOb
)
296 il
.Emit(OpCodes
.Call
, Typeob
.GlobalObject
.GetProperty("URIError").GetGetMethod());
298 il
.Emit(OpCodes
.Call
, Typeob
.GlobalObject
.GetProperty("Error").GetGetMethod());
299 Convert
.Emit(this, il
, Typeob
.ScriptFunction
, rtype
);
300 }else if (val
is FunctionConstructor
){
301 il
.Emit(OpCodes
.Call
, Typeob
.GlobalObject
.GetProperty("Function").GetGetMethod());
302 Convert
.Emit(this, il
, Typeob
.ScriptFunction
, rtype
);
303 }else if (val
is MathObject
){
304 il
.Emit(OpCodes
.Call
, Typeob
.GlobalObject
.GetProperty("Math").GetGetMethod());
305 Convert
.Emit(this, il
, Typeob
.JSObject
, rtype
);
306 }else if (val
is NumberConstructor
){
307 il
.Emit(OpCodes
.Call
, Typeob
.GlobalObject
.GetProperty("Number").GetGetMethod());
308 Convert
.Emit(this, il
, Typeob
.ScriptFunction
, rtype
);
309 }else if (val
is ObjectConstructor
){
310 il
.Emit(OpCodes
.Call
, Typeob
.GlobalObject
.GetProperty("Object").GetGetMethod());
311 Convert
.Emit(this, il
, Typeob
.ScriptFunction
, rtype
);
312 }else if (val
is RegExpConstructor
){
313 il
.Emit(OpCodes
.Call
, Typeob
.GlobalObject
.GetProperty("RegExp").GetGetMethod());
314 Convert
.Emit(this, il
, Typeob
.ScriptFunction
, rtype
);
315 }else if (val
is StringConstructor
){
316 il
.Emit(OpCodes
.Call
, Typeob
.GlobalObject
.GetProperty("String").GetGetMethod());
317 Convert
.Emit(this, il
, Typeob
.ScriptFunction
, rtype
);
318 }else if (val
is VBArrayConstructor
){
319 il
.Emit(OpCodes
.Call
, Typeob
.GlobalObject
.GetProperty("VBArray").GetGetMethod());
320 Convert
.Emit(this, il
, Typeob
.ScriptFunction
, rtype
);
321 }else if (val
is IntPtr
){
322 il
.Emit(OpCodes
.Ldc_I8
, (long)(IntPtr
)val
);
323 il
.Emit(OpCodes
.Conv_I
);
324 Convert
.Emit(this, il
, Typeob
.IntPtr
, rtype
);
325 }else if (val
is UIntPtr
){
326 il
.Emit(OpCodes
.Ldc_I8
, (long)(UIntPtr
)val
);
327 il
.Emit(OpCodes
.Conv_U
);
328 Convert
.Emit(this, il
, Typeob
.UIntPtr
, rtype
);
329 }else if (val
is Missing
){
330 il
.Emit(OpCodes
.Ldsfld
, CompilerGlobals
.missingField
);
331 Convert
.Emit(this, il
, Typeob
.Object
, rtype
);
332 }else if (val
is System
.Reflection
.Missing
){
333 if (rtype
.IsPrimitive
)
334 this.TranslateToIL(il
, Double
.NaN
, rtype
);
335 else if (rtype
!= Typeob
.Object
&& !rtype
.IsValueType
)
336 il
.Emit(OpCodes
.Ldnull
);
338 il
.Emit(OpCodes
.Ldsfld
, CompilerGlobals
.systemReflectionMissingField
);
339 Convert
.Emit(this, il
, Typeob
.Object
, rtype
);
341 }else if (val
!= this.value) //Value was coerced to some type we have no compile time knowlegde of
342 this.TranslateToIL(il
, this.value, rtype
);
344 throw new JScriptException(JSError
.InternalError
, this.context
); //It should not be possible to wrap any other kind of object
347 internal static void TranslateToILInt(ILGenerator il
, int i
){
349 case -1:il
.Emit(OpCodes
.Ldc_I4_M1
); break;
350 case 0: il
.Emit(OpCodes
.Ldc_I4_0
); break;
351 case 1: il
.Emit(OpCodes
.Ldc_I4_1
); break;
352 case 2: il
.Emit(OpCodes
.Ldc_I4_2
); break;
353 case 3: il
.Emit(OpCodes
.Ldc_I4_3
); break;
354 case 4: il
.Emit(OpCodes
.Ldc_I4_4
); break;
355 case 5: il
.Emit(OpCodes
.Ldc_I4_5
); break;
356 case 6: il
.Emit(OpCodes
.Ldc_I4_6
); break;
357 case 7: il
.Emit(OpCodes
.Ldc_I4_7
); break;
358 case 8: il
.Emit(OpCodes
.Ldc_I4_8
); break;
360 if (-128 <= i
&& i
<= 127)
361 il
.Emit(OpCodes
.Ldc_I4_S
, (SByte
)i
);
363 il
.Emit(OpCodes
.Ldc_I4
, i
);
368 internal override void TranslateToILInitializer(ILGenerator il
){